﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WXClear
{
    public partial class FrmMain : Sunny.UI.UIForm
    {
        static readonly string DEFAULTPATH = "WeChat Files";
        int FINDCOUNT = 0;
        int INITVIEW = 0;
        readonly int FINDTARGETCOUNT = 3;
        readonly Sunny.UI.UIStatusForm m_UIStatusForm;

        public FrmMain()
        {
            InitializeComponent();
            this.Width = 800;
            this.Height = 600;
            m_UIStatusForm = new Sunny.UI.UIStatusForm
            {
                TopMost = true,
                TopLevel = true
            };
        }

        protected override void OnLoad(EventArgs e)
        {
            this.m_LabelMessage.Text = string.Empty;
            base.OnLoad(e);
            m_WXFilesPathTextBox.Text = FindDefaultPath();
            this.m_PathBrowerBtn.Click += PathBrowerBtn_Click;
            this.m_FindRepeatBtn.Click += FindRepeatBtn_Click;
            this.m_DelBtn.Click += DelBtn_Click;

            this.m_UICheckBoxDocs.ValueChanged += UICheckBoxDocs_ValueChanged;
            this.m_UICheckBoxImages.ValueChanged += UICheckBoxImages_ValueChanged;
            this.m_UICheckBoxVideos.ValueChanged += UICheckBoxVideos_ValueChanged;

            this.ExtendBoxClick += FrmMain_ExtendBoxClick;
        }

        private void FrmMain_ExtendBoxClick(object sender, EventArgs e)
        {
            FormAbout fa = new FormAbout();
            fa.Show();
        }

        private void UICheckBoxVideos_ValueChanged(object sender, bool value)
        {
            m_UITextBoxVideos.Enabled = value;
        }

        private void UICheckBoxImages_ValueChanged(object sender, bool value)
        {
            m_UITextBoxImages.Enabled = value;
        }

        private void UICheckBoxDocs_ValueChanged(object sender, bool value)
        {
            m_UITextBoxDocs.Enabled= value;
        }

        void DelBtn_Click(object sender, EventArgs e)
        {
            var dr = MessageBox.Show("确认要删除选中项目吗？", "警告", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
            if (dr == System.Windows.Forms.DialogResult.OK)
            {
                ShowInfo("开始删除");
                m_UIStatusForm.Show();
                m_UIStatusForm.Show();
                Del(this.m_ListViewDoc);
                Del(this.m_ListViewImage);
                Del(this.m_ListViewVideo);
                ShowInfo("删除完成");
                m_UIStatusForm.Hide();
                FindRepeatFile();
            }
        }

        void Del(ListView lv) 
        {
            foreach (ListViewItem item in lv.Items)
            {
                if (item.Checked)
                {
                    string path = item.SubItems[4].Text;
                    File.Delete(path);
                }
            }
        }

        void FindRepeatBtn_Click(object sender, EventArgs e)
        {
            if (!Directory.Exists(this.m_WXFilesPathTextBox.Text))
            {
                ShowErr("路径不存在 ： " + this.m_WXFilesPathTextBox.Text);
            }
            FindRepeatFile();
        }

        public void ShowInfo(string info)
        {
            this.m_LabelMessage.Text = info;
            this.m_LabelMessage.ForeColor = Color.Black;
        }
        public void ShowErr(string err)
        {
            this.m_LabelMessage.Text = err;
            this.m_LabelMessage.ForeColor = Color.Red;
        }

        void FindRepeatFile()
        {
            this.m_ListViewDoc.Items.Clear();
            this.m_ListViewImage.Items.Clear();
            this.m_ListViewVideo.Items.Clear();
            ShowInfo("正在查找....");
            m_UIStatusForm.Show();
            var dir = new DirectoryInfo(this.m_WXFilesPathTextBox.Text.Replace("\\", "/"));
            List<FileInformation> docs = new List<FileInformation>(), images = new List<FileInformation>(), videos = new List<FileInformation>();
            Task.Factory.StartNew(() =>
            {
                List<string> keys = new List<string>(m_UITextBoxDocs.Text.Split(','));
                GetAllFiles(dir, keys, docs);
            }).ContinueWith(t =>
            {
                FINDCOUNT++;
                FindConplete();
                AddToListView(this.m_ListViewDoc, docs);
                INITVIEW++;
                FindConplete();
            },
            System.Threading.CancellationToken.None,
            TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());

            Task.Factory.StartNew(() =>
            {
                List<string> keys = new List<string>(m_UITextBoxImages.Text.Split(','));
                GetAllFiles(dir, keys, images);
            }).ContinueWith(t =>
           {
               FINDCOUNT++;
               FindConplete();
               AddToListView(this.m_ListViewImage, images);
               INITVIEW++;
               FindConplete();
           },
            System.Threading.CancellationToken.None,
            TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());

            Task.Factory.StartNew(() =>
            {
                List<string> keys = new List<string>(m_UITextBoxVideos.Text.Split(','));
                GetAllFiles(dir, keys, videos);
            }).ContinueWith(t =>
            {
                FINDCOUNT++;
                FindConplete();
                AddToListView(this.m_ListViewVideo, videos);
                INITVIEW++;
                FindConplete();
            },
            System.Threading.CancellationToken.None,
            TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
        }
        void FindConplete()
        {
            if (FINDCOUNT == FINDTARGETCOUNT)
            {
                ShowInfo("查找完成，开始初始化列表");
                FINDCOUNT = 0;
            }
            if (INITVIEW == FINDTARGETCOUNT)
            {
                ShowInfo("查找重复项完成");
                INITVIEW = 0;
                m_UIStatusForm.Hide();
            }
        }
        void AddToListView(ListView lv, List<FileInformation> files)
        {
            List<FileInformation> newFiles = Sort(files);
            int index = 1;
            FileInformation lastFile = null;
            ListViewItem LastLvi = null;
            foreach (var fi in newFiles)
            {
                ListViewItem item = new ListViewItem
                {
                    Text = string.Empty + index++
                };
                item.SubItems.Add(fi.FileName);
                item.SubItems.Add(string.Empty + fi.Size);
                item.SubItems.Add(fi.DateStr);
                item.SubItems.Add(fi.FilePath);
                if (lastFile == null)
                {
                    item.BackColor = GetRandomColor();
                }
                else if ((lastFile.MD5Str != fi.MD5Str))
                {
                    item.BackColor = GetRandomColor();
                }
                else
                {
                    item.BackColor = LastLvi.BackColor;
                    if (m_RadioButtonOld.Checked)
                    {
                        item.Checked = true;
                    }
                }
                lv.Items.Add(item);//显示
                lastFile = fi;
                LastLvi = item;
            }
        }
        static Color[] AllCOlors
        {
            get
            {
                Array Colors = System.Enum.GetValues(typeof(System.Drawing.KnownColor));
                List<Color> cs = new List<Color>();
                foreach (var c in Colors)
                {
                    string cName = c.ToString();
                    if (cName.StartsWith("L") || cName.StartsWith("Y")|| cName.StartsWith("G")) {
                        cs.Add(System.Drawing.Color.FromName(cName));
                    }
                }
                return cs.ToArray();
            }
        }
        public static Color GetRandomColor()
        {
            Random RandomNum_First = new Random((int)DateTime.Now.Ticks);
            RandomNum_First.Next(4);
            //  为了在白色背景上显示，尽量生成深色
            int randomNum = RandomNum_First.Next(AllCOlors.Length-1);
            return AllCOlors[randomNum];
        }

        void PathBrowerBtn_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog
            {
                Description = "请选择文件路径"
            };
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                string foldPath = dialog.SelectedPath;
                this.m_WXFilesPathTextBox.Text = foldPath;
            }
        }

        private string FindDefaultPath()
        {
            string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            //path = path.Replace("\\","/");
            string defaultFullPath = path + "\\" + DEFAULTPATH;
            
            bool isWeChatFilesExist = Directory.Exists(defaultFullPath);
            if (isWeChatFilesExist)
            {
                return defaultFullPath;
            }
            return string.Empty;
        }
        public void GetAllFiles(DirectoryInfo dir, List<string> keys, List<FileInformation> result )
        {
            try
            {
                FileInfo[] tmp;
                List<FileInfo> allFile = new List<FileInfo>();
                foreach (var k in keys)
                {
                    tmp = dir.GetFiles("*" + k, SearchOption.TopDirectoryOnly);
                    allFile.AddRange(tmp);
                }
                foreach (FileInfo fi in allFile)
                {
                    if (keys.Contains(Path.GetExtension(fi.FullName)))
                    {
                        lock (this)
                        {
                            result.Add(new FileInformation
                            {
                                FileName = fi.Name,
                                FilePath = fi.FullName,
                                MD5Str = GetMD5HashFromFile(fi.FullName),
                                Size = fi.Length,
                                DateStr = fi.LastWriteTime.ToString("yyyy-MM-dd hh:mm:ss"),
                                LastName = Path.GetExtension(fi.FullName)
                            });
                        }
                    }
                }
                DirectoryInfo[] allDir = dir.GetDirectories();
                foreach (DirectoryInfo d in allDir)
                {
                    GetAllFiles(d, keys, result);
                }
            }
            catch(Exception ex)
            {
                Sunny.UI.UIMessageTip.Show("发生错误" + ex.Message,Sunny.UI.TipStyle.Red);
            }
        }

        public class FileInformation
        {
            public string FileName { get; set; }
            public string FilePath { get; set; }

            public long Size { get; set; }

            public string DateStr { get; set; }
            public string MD5Str { get; set; }

            public string LastName { get; set; }
        }

        public List<FileInformation> Sort(List<FileInformation> files)
        {
            List<FileInformation> lFiles = new List<FileInformation>(files.ToArray());
            lFiles.Sort(SortListMd5);
            return lFiles;
        }
        private int SortListMd5(FileInformation a, FileInformation b) //a b表示列表中的元素
        {
            if (a.MD5Str == b.MD5Str)
            {
                return 2;
            }
            else
            {
                if (m_RadioButtonOld.Checked)
                {
                    return string.Compare(a.DateStr, b.DateStr, false);
                }
                else
                {
                    if (a.Size > b.Size) return 1;
                    else return 0;
                }
            }
        }
        public static string GetMD5HashFromFile(string fileName)
        {
            try
            {
                FileStream file = new FileStream(fileName, FileMode.Open);
                System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] retVal = md5.ComputeHash(file);
                file.Close();

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < retVal.Length; i++)
                {
                    sb.Append(retVal[i].ToString("x2"));
                }
                return sb.ToString();
            }
            catch (Exception ex)
            {
                throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message);
            }
        }
    }
}
